package ws.very.util.lang

import scala.collection.immutable.StringOps
import scala.util.{Success, Try}
import java.io.File
import java.net.URI

import scala.collection.convert.WrapAsScala
import java.util.concurrent.Callable

import scala.collection.TraversableLike
import scala.collection.SeqLike
import scala.collection.GenTraversableOnce
import scala.collection.generic.CanBuildFrom
import scala.reflect.ClassTag
import java.text.DateFormat
import java.util.Date

import ShortTypes._

import scala.math.Ordering
import scala.reflect

@deprecated
trait ImplicitCookies extends WeekBooleanCookies with ShortType with WeekOption {

  object <> {
    def ?[A](a: A) = Option(a)

    def ex[A](fn: => A) = Try(fn)
  }

}

object Implicits2 extends Implicits2

trait Implicits2 extends WeekBooleanCookies with ShortType with WeekOption
  with WeekCollCookies with StrConversion with WrapAsScala with ThreadConverter
  with FnCookies with RichIO with CaseLang with StrCookies with Testing {

}

trait WeekOption {
  implicit def anyToOption[R](x: R) = Option(x)

  implicit class ToOption[R: reflect.ClassTag](x: R) {
    def toOption = Option(x)
  }

}

object WeekOption extends WeekOption

trait WeekCollCookies {
  implicit def any2Coll[T](any: T) = Iterable(any)
}

trait RichOption {

  implicit class OptionEx[T,O <% Option[T] ](v: O) {
    def matchTo[R](someFn: (T => R), elseVal: => R) =
      v match {
        case Some(v:T) => someFn(v)
        case _ => elseVal
      }
  }

}

trait RichTry {

  implicit class TryEx[T,O <% Try[T]](v: O) {
    def matchTo[R](successFn: (T => R), elseVal: => R) =
      v match {
        case Success(v:T) => successFn(v)
        case _ => elseVal
      }
  }

}

trait RichIt {

  implicit class RithGroupCount[A, Repr <% TraversableOnce[A]](t: TraversableLike[A, Repr]) { //FIXME:it can't work (new java.util.ArrayList[String]).groupSelfCount
    def groupSelfCount = t.groupBy(identity).mapValues(_.size)
  }

  implicit class RichSortVal[K, V, Repr](it: SeqLike[(K, V), Repr]) { //FIXME:sorted?sortWith?
    def sortByVal(implicit ord: Ordering[V]) = it.sortBy { a => a._2 }


  }

  implicit class RichSort[X, CC[T] <: Seq[T]](t: CC[X]) {
    // SeqLike[T,CC[T]]

    def sortDescBy[B](f: X => B)(implicit ord: Ordering[B]) =
      t.sortBy(f)(ord.reverse)

    def sortedDesc[B >: X](implicit ord: Ordering[B]) = t.sorted(ord.reverse)


    def rankingBy[B](f: X => B, sortByDesc: Boolean = false, initNo: I = 1)(implicit ord: Ordering[B]) = {
      val base = t.groupBy(f(_)).toSeq.sortBy {
        _._1
      }(if (sortByDesc) ord.reverse else ord).map {
        _._2
      }

      def sorting[T](coll: Seq[Iterable[T]], curNo: I = initNo, collect: Seq[(I, T)] = Nil): Seq[(I, T)] =
        if (coll.nonEmpty) {
          val head :: other = coll.toList
          val result = collect ++ head.map { t => curNo -> t }

          sorting(other, curNo + head.size, result)

        } else collect

      sorting(base)
    }


  }

  trait OptionOrdering[T] extends Ordering[Option[T]] {
    def optionOrdering: Ordering[T]

    def compare(x: Option[T], y: Option[T]) = (x, y) match {
      case (None, None) => 0
      case (None, _) => 1
      case (_, None) => -1
      case (Some(x), Some(y)) => optionOrdering.compare(x, y)
    }
  }

  def noneIsMax[T](implicit ord: Ordering[T]): Ordering[Option[T]] =
    new OptionOrdering[T] {
      val optionOrdering = ord
    }

  //  implicit class MapFilter[T, IT[+T] >: Iterable[T]](i: IT[T]) {
  //
  //    def mapAndFilter[R](fn: T => Option[R]):IT[R] =
  //      i.map { fn }.filter { _.nonEmpty }.map { _.get }
  //  }

  //  class RighJoin[T, A <: Iterable[T]](t: Iterable[A]) {
  //        def join[That](implicit bf: CanBuildFrom[A, A, A]) = t.flatMap(identity)(bf)
  //  }
  //  
  //
  //Iterable(Iterable("")).flatMap(identity)
  //new RighJoin( Iterable(Iterable("")))
  // val t=  new RighJoin( Iterable(Iterable(""))).join
  //  new MapFilter(List[S]())
  //  val w = List[S]().filter(t => true).map(t => t)
  //  val f = List[S]().mapAndFilter(Option(_))
}

trait DateCookies {

  import scala.concurrent.duration._

  object now {
    def mill = System.currentTimeMillis()

    def sec = mill / 1000
  }

  implicit class Formater(f: DateFormat) {
    def formatNow = f.format(new Date)
  }

  implicit def duration2Date(d: Duration) = new Date(d.toMillis)

  implicit def date2Duration(d: Date) = d.getTime().milli
}

trait SysPropCookies {

  import WeekOption._

  def sysProp(p: String) = System.getProperty(p).toOption

  object sysProp {
    def apply(p: String) = get(p).toOption

    def get(p: String) = System.getProperty(p)

    lazy val fileEncoding = get("file.encoding")
  }

}

trait StrCookies {

  implicit class StrImpl(str: String) {
    def delAll(txt: S) = str.replaceAll(txt, "")

    def delAllNewLine = delAll(Texts.Regex.Line)

    @deprecated
    def delNewLine = delAllNewLine


    /*
    str="19991111"
    counts= 4，2
    result=[1999,11,11]
    FIXME:应该由集合类实现
     */
    def splitByCount(counts: I*) = {
      var curStr = str
      counts.map { c =>
        val (head, tail) = curStr.splitAt(c)
        curStr = tail

        head
      }.toList ::: (curStr :: Nil)
    }

    /**
      * 和split区别
      * 字符串"2005-05-09",,,,,100.0374,,,,
      * split.length=6
      * splitFull.length=10
      *
      * @param code
      * @param i
      * @return
      */
    def splitFull(code: S, i: I = 0): List[S] = {
      val index = str.indexOf(code, i)

      if (index >= i)
        str.substring(i, index) :: splitFull(code, index + 1)
      else str.substring(i, str.length) :: Nil
    }
  }

}

object SysPropCookies extends SysPropCookies

trait EitherCookies {
  implicit def uniqueVal[T](select: T | T) = select match {
    case Left(t) => t
    case Right(t) => t
  }

  implicit def toLeft[L, R](left: L): Either[L, R] = Left(left)

  implicit def toRight[L, R](right: R): Either[L, R] = Right(right)

  implicit class RightProjectionExt[L, R](right: Either.RightProjection[L, R]) {
    def convert[NR](right2NewEither: R => Either[L, NR]) = right.e match {
      case Right(r) => right2NewEither(r)
      case Left(l) => Left(l)
    }
  }

  implicit class LeftProjectionExt[L, R](left: Either.LeftProjection[L, R]) {
    def convert[NL](left2NewEither: L => Either[NL, R]) = left.e match {
      case Right(r) => Right(r)
      case Left(l) => left2NewEither(l)
    }
  }

}

trait Testing extends RichIt with ShortType2 with DateCookies with SysPropCookies with EitherCookies with RichOption with RichTry{

  object WeekType extends WeekTypeCookies //使在作用域使用import

  implicit class ElvisOp[T](t: T) {
    def ?:[A >: T](other: => A) = if (t == null) other else t

    def ?=[A >: T](other: => A) = ?:(other)

    def ??=[A >: T](other: => A)(implicit isNotEmpty: T => B) = if (isNotEmpty(t)) t else other

    def ??:[A >: T](other: => A)(implicit isNotEmpty: T => B) = ??=(other)
  }

  type Nullable[A >: Null] = A

  /*
 * 现在它需要明确返回值才可生效
 *   val t: (I => I) = if (1 == 1)
    (i: I) => 1
  else 1
 */
  implicit def fixedFn[F, T, G >: T](t: G) = { (f: F) => t }

}










